package se

import (
	"strings"

	"gitee.com/xuender/oils/level"
	"gitee.com/xuender/oils/logs"
	"gitee.com/xuender/oils/sets"
	"gitee.com/xuender/oils/u32"
	"gitee.com/xuender/se/pb"
)

// WordService 词服务.
type WordService struct {
	ls           *level.Service
	wordIDSeq    [2]byte      // 词ID序列
	wordPrefix   [2]byte      // 词前缀
	wordIDPrefix [2]byte      // 词ID对应的词信息
	wordsKey     [2]byte      // 词组
	words        sets.Strings // 词组
	wordsMap     map[string]sets.Strings
}

// NewWordService 新建词服务.
func NewWordService(ls *level.Service) *WordService {
	wordsKey := [2]byte{ByteWord, ByteWord}
	words := sets.NewStrings()

	ls.Get(wordsKey[:], &words)

	return &WordService{
		ls:           ls,
		wordIDSeq:    [2]byte{ByteSeq, ByteWord},
		wordPrefix:   [2]byte{ByteWord, BytePrefix},
		wordIDPrefix: [2]byte{ByteWord, ByteID},
		words:        words,
		wordsMap:     make(map[string]sets.Strings),
		wordsKey:     wordsKey,
	}
}

// Word 词的主键.
func (p *WordService) Word(word string, create bool) uint32 {
	return p.word(word, create, p.wordIDSeq)
}

// Word 词的主键.
func (p *WordService) word(word string, create bool, seqKey [2]byte) uint32 {
	word = strings.ToLower(word)
	key := p.wordPrefix[:]
	key = append(key, []byte(word)...)

	has := logs.PanicBool(p.ls.DB.Has(key, nil))
	if has {
		id := uint32(0)

		p.ls.Get(key, &id)

		return id
	}

	if !create {
		return 0
	}

	id := p.ls.NextSequence(seqKey[:])

	logs.Info("WORD:", word, id)
	p.ls.Put(key, id)

	idKey := p.wordIDPrefix[:]
	idKey = append(idKey, u32.Bytes(id)...)
	wordInfo := &pb.Word{
		Id:   id,
		Word: word,
	}

	p.ls.Put(idKey, wordInfo)

	return id
}

func (p *WordService) wordIDs(set sets.Strings) []uint32 {
	wordIDs := []uint32{}

	for s := range set {
		if id := p.Word(s, false); id > 0 {
			wordIDs = append(wordIDs, id)
		}
	}

	return wordIDs
}

func (p *WordService) wordStrings(idSet sets.Uint32s) []string {
	words := []string{}

	for id := range idSet {
		key := p.wordIDPrefix[:]
		key = append(key, u32.Bytes(id)...)
		info := &pb.Word{}

		if p.ls.Get(key, info) {
			words = append(words, info.Word)
		}
	}

	return words
}

// Words 根据id获取词信息.
func (p *WordService) Words(ids []uint32) []*pb.Word {
	ret := []*pb.Word{}
	idKey := make([]byte, 6)

	copy(idKey, p.wordIDPrefix[:])

	for _, id := range ids {
		bs := u32.Bytes(id)

		for i := 0; i < 4; i++ {
			idKey[i+2] = bs[i]
		}

		wi := &pb.Word{}
		if p.ls.Get(idKey, wi) {
			ret = append(ret, wi)
		}
	}

	return ret
}
